﻿using System;
using System.Transactions;

namespace Sample.Common.Transaction
{
    public sealed class TransactionScopeWrapper : TransactionScopeAbstractWrapper
    {
        private readonly TransactionScope _scope;
        private bool _isDisposed;

        public TransactionScopeWrapper()
            : this(TransactionScopeOption.Required,
                IsolationLevel.ReadCommitted,
                new TimeSpan(0, 0, 30))
        {
        }

        public TransactionScopeWrapper(TransactionScopeOption scopeOption)
            : this(scopeOption,
                IsolationLevel.ReadCommitted,
                new TimeSpan(0, 0, 30))
        {
        }

        public TransactionScopeWrapper(IsolationLevel isolationLevel)
            : this(TransactionScopeOption.Required,
                isolationLevel,
                new TimeSpan(0, 0, 30))
        {
        }

        public TransactionScopeWrapper(TimeSpan timeout)
            : this(TransactionScopeOption.Required,
                IsolationLevel.ReadCommitted,
                timeout)
        {
        }

        public TransactionScopeWrapper(TransactionScopeOption scopeOption,
            IsolationLevel isolationLevel,
            TimeSpan timeout) :
            base(scopeOption, isolationLevel, timeout)
        {
            _scope = new TransactionScope(ScopeOption,
                new TransactionOptions { IsolationLevel = IsolationLevel, Timeout = Timeout }
                );

            IsCompleted = false;
        }

        public override bool IsCompleted { get; protected set; }

        public new static TransactionScopeAbstractWrapper Current
        {
            get { return TransactionScopeAbstractWrapper.Current; }
        }

        protected override void Dispose(bool isDisposing)
        {
            if (!_isDisposed)
            {
                if (isDisposing)
                {
                    _scope.Dispose();
                }

                _isDisposed = true;
            }
        }

        public override void Complete()
        {
            var current = Current;

            if (current == null)
            {
                throw new InvalidOperationException("Unable to find out root scope"); //todo, Resources.UnableToFindOutRootScope
            }
            if (this != current
                && (current.IsDisposed
                    || current.IsCompleted))
            {
                throw new InvalidOperationException(string.Format("Root Scope already is {0}",
                    (current.IsDisposed ? "disposed." : "completed"))); //todo,Resources.UnavailableRootScope
            }
            _scope.Complete();
            IsCompleted = true;
        }
    }
}